/**
 * 
 */
package org.bankabeule.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.bankabeule.Account;
import org.bankabeule.Model;
import org.bankabeule.util.Utils;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;

/**
 * @author sdudoit
 * 
 */
public class ModelManager {

	/**
	 * ModelManager model file extension
	 */
	public static final String FILE_EXTENSION = "bankabeule";

	/**
	 * Singleon instance
	 */
	private static ModelManager instance = null;

	/**
	 * Current model open
	 */
	private Model model = null;
	
	/**
	 * dirty flag
	 */
	private boolean isModelDirty = false;

	/**
	 * Model listeners
	 */
	private List<ModelListener> listeners = null;

	/**
	 * Private constructor
	 */
	private ModelManager() {
		listeners = new ArrayList<ModelListener>();
	}

	/**
	 * Get singleton instance
	 */
	public static ModelManager get() {
		if (instance == null) {
			instance = new ModelManager();
		}
		return instance;
	}

	/**
	 * Get current model loaded
	 */
	public Model getModel() {
		return model;
	}

	/**
	 * Load model
	 */
	public void load(String path) throws Exception {
		if (model != null) {
			unload();
		}
		System.out.println("ModelManager: load "+path);	
		// reset dirty flag
		isModelDirty = false;
		// load new model
		URI uri = URI.createFileURI(path);
		ResourceSet resourceSet = new ResourceSetImpl();
		Resource resource = resourceSet.getResource(uri, true);
		resource.setTrackingModification(true);
		resource.eAdapters().add(new AdapterImpl(){
			public void notifyChanged(Notification notification) {
				if (notification.getNotifier() instanceof Resource) {
					if (((Resource) notification.getNotifier()).isModified()) {
						if (!isModelDirty) {
							ModelManager.get().setDirty();
						}
					}
				}
			}
		});
		// get model
		model = (Model) resource.getContents().get(0);
		// calculate value of all accounts
		for (Account account : model.getAccounts()) {
			Utils.calculateValue(account);
		}
		// inform listeners
		for (ModelListener listener : listeners) {
			listener.modelLoaded(model);
		}		
	}

	/**
	 * Unload model loaded
	 */
	public void unload() throws Exception {
		System.out.println("ModelManager: unload "+model.eResource().getURI().toFileString());	
		// inform listeners
		for (ModelListener listener : listeners) {
			listener.modelUnloaded(model);
		}
		// reset model
		isModelDirty = true;
		model.eResource().unload();
		model = null;
		// reset dirty flag
		isModelDirty = false;
	}


	/**
	 * Is dirty
	 */
	public boolean isDirty() {
		return isModelDirty;
	}

	
	/**
	 * Dirty model loaded
	 */
	public void setDirty() {
		System.out.println("ModelManager: set dirty "+model.eResource().getURI().toFileString());	
		if (!isModelDirty) {
			System.out.println("ModelManager: really set dirty "+model.eResource().getURI().toFileString());	
			isModelDirty = true;
			for (ModelListener listener : listeners) {
				listener.modelDirty(model);
			}
		}
	}
	
	
	/**
	 * Save model loaded
	 */
	public void save() throws Exception {
		System.out.println("ModelManager: save "+model.eResource().getURI().toFileString());	
		if (isModelDirty) {
			System.out.println("ModelManager: really save "+model.eResource().getURI().toFileString());	
			model.eResource().save(Collections.EMPTY_MAP);
			isModelDirty = false;
			for (ModelListener listener : listeners) {
				listener.modelSaved(model);
			}
		}
	}

	/**
	 * Add model listener
	 */
	public void addModelListener(ModelListener listener) {
		listeners.add(listener);			
	}

	/**
	 * Remove model listener
	 */
	public void removeModelListener(ModelListener listener) {
		listeners.remove(listener);
	}


}
